package com.itchen.school.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.*;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.itchen.school.common.base.BaseService;
import com.itchen.school.common.constant.Constants;
import com.itchen.school.common.exception.SysException;
import com.itchen.school.common.utils.DateUtils;
import com.itchen.school.common.utils.ExcelExportUtils;
import com.itchen.school.common.utils.ExcelHelper;
import com.itchen.school.common.utils.SysDateUtils;
import com.itchen.school.dao.TbStudentMapper;
import com.itchen.school.entities.TbStudent;
import com.itchen.school.entities.vo.TbStudentVo;
import com.itchen.school.service.ITbStudentService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;

import static org.apache.tomcat.util.buf.StringUtils.join;

@Service
public class TbStudentService extends BaseService<TbStudentMapper, TbStudent> implements ITbStudentService {

    @Override
    @Transactional(readOnly = true)
    public List<TbStudent> getStudentList() {
        LambdaQueryWrapper<TbStudent> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.ne(TbStudent::getRecordStatus, Constants.DATA_DELETED);
        lambdaQueryWrapper.orderByDesc(TbStudent::getCreateTime);
        return ref(TbStudentMapper.class).selectList(lambdaQueryWrapper);
    }

    @Override
    @Transactional
    public boolean saveStudent(TbStudent student) {
        if (ObjectUtils.isEmpty(student)) {
            throw new SysException("参数有误，请重新输入！");
        }
        // 1.设置主键
        student.setId(IdWorker.get32UUID());
        // 2.统一检查输入的数据格式
        checkData(student);
        // 3.保存信息
        return baseMapper.insert(student) > 0;
    }

    @Override
    @Transactional(readOnly = true)
    public TbStudent getStudentOne(String id) {
        LambdaQueryWrapper<TbStudent> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StringUtils.isNotEmpty(id), TbStudent::getId, id);
        TbStudent tbStudent = baseMapper.selectOne(lambdaQueryWrapper);
        if (ObjectUtils.isEmpty(tbStudent)) {
            throw new SysException("系统错误，请联系管理员！");
        }
        return tbStudent;
    }

    @Override
    @Transactional
    public boolean editStudent(TbStudent student) {
        if (ObjectUtils.isEmpty(student)) {
            throw new SysException("参数有误，请重新输入！");
        }
        // 1.统一检查输入的数据格式
        checkData(student);
        // 2.保存信息
        return baseMapper.updateById(student) > 0;
    }

    // 统一检查输入的数据格式
    private void checkData(TbStudent student){
        if (StringUtils.isEmpty(student.getId())) {
            throw new SysException("系统错误，请联系管理员！");
        }
        if (StringUtils.isEmpty(student.getName())) {
            throw new SysException("学生姓名不能为空！");
        }
    }

    @Override
    @Transactional
    public boolean deleteStudent(List<String> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new SysException("参数有误，请重新输入！");
        }
        // 1.根据用品id修改用品状态
        LambdaUpdateWrapper<TbStudent> updateWrapper = new LambdaUpdateWrapper<>();
        // 2.将用品状态设置为0
        updateWrapper.eq(TbStudent::getId, ids.get(0))
                .set(TbStudent::getRecordStatus, Constants.DATA_DELETED);
        // 3.逻辑删除用品信息
        return baseMapper.update(null, updateWrapper) > 0;
    }

    @Override
    @Transactional
    public boolean ToggleRecordStatus(List<String> ids, Integer toggle) {
        List<TbStudent> studentList = baseMapper.selectBatchIds(ids);
        // 启用
        if (toggle.equals(Constants.DATA_VALID)) {
            studentList.forEach(x->{
                x.setRecordStatus(Constants.DATA_VALID);
                baseMapper.updateById(x);
            });
        // 禁用
        } else if (toggle.equals(Constants.DATA_INVALID)) {
            studentList.forEach(x->{
                x.setRecordStatus(Constants.DATA_INVALID);
                baseMapper.updateById(x);
            });
        }
        return true;
    }

    @Override
    @Transactional
    public String importTbStudentList(File fileTemp) {
        // 检查excel文件头部列表
        try {
            ExcelHelper excelHelper = new ExcelHelper(fileTemp);
            String[] heads = new String[]{"学生学号","学生姓名","学生性别","出生日期","学生年龄","学生宿舍","班级名称","年级名称","学院名称"};
            checkExcelHead(excelHelper, heads);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 获取导入数据
        List<TbStudentVo> importData = ExcelExportUtils.importExcel(fileTemp, TbStudentVo.class);
        if (CollectionUtils.isEmpty(importData)) throw new SysException("导入失败，导入数据为空，请修改后重新导入！");
        // 有空值的不合规数据
        List<TbStudent> failureData = Lists.newArrayList();
        // 需要插入的数据
        List<TbStudent> insertData = Lists.newArrayList();
        // 检查导入的数据
        importData.forEach( x-> checkImportData(failureData, insertData, x));
        // 需要覆盖和插入的数据
        Map<String, List<TbStudent>> updateMap = Maps.newHashMap();
        updateMap.put("insert", insertData);
        updateMap.put("failure", failureData);
        // 保存数据
        return saveImportData(updateMap);
    }

    // 检查请求头
    private void checkExcelHead(ExcelHelper excelHelper, String[] heads) {
        List<String> title = excelHelper.getHeadRows(0, 0, 0, -1);
        if (CollectionUtils.isEmpty(title)) throw new SysException("导入失败，导入的文件表头字段名与导入模板不一致，请重新下载导入模板", "＜模板缺少列头＞");
        for (int i = 0; i < title.size(); i++) {
            if (!title.get(i).equals(heads[i])) {
                throw new SysException("导入失败，导入的文件表头字段名与导入模板不一致，请重新下载导入模板", "导入文件列头跟模板列头没有一一对应");
            }
        }
    }

    // 检查导入的数据
    private void checkImportData(List<TbStudent> failureData, List<TbStudent> insertData, TbStudentVo studentVo) {
        // 记录保存对象
        TbStudent student = new TbStudent();
        // 导入返回excel失败信息
        List<String> failureReasonContent = Lists.newArrayList();
        student.setId(IdWorker.get32UUID());

        if (StringUtils.isNotEmpty(studentVo.getNumber())) {
            student.setNumber(studentVo.getNumber());
        } else {
            failureReasonContent.add("' 学生学号 '不能为空！");
        }

        if (StringUtils.isNotEmpty(studentVo.getName())) {
            student.setName(studentVo.getName());
        } else {
            failureReasonContent.add("' 学生姓名 '不能为空！");
        }

        if (StringUtils.isNotEmpty(studentVo.getSex())) {
            if ("男".equals(studentVo.getSex())) {
                student.setSex(1);
            } else if ("女".equals(studentVo.getSex())){
                student.setSex(0);
            } else {
                student.setSexStr(studentVo.getSex());
                failureReasonContent.add("' 学生性别 '填写有误！");
            }
        } else {
            failureReasonContent.add("' 学生性别 '不能为空！");
        }

        if (StringUtils.isNotEmpty(studentVo.getBirthday())) {
            try {
                long toLong = SysDateUtils.getToLong(studentVo.getBirthday(), "yyyy-MM-dd HH:mm");
                student.setBirthday(toLong);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            failureReasonContent.add("' 出生日期 '不能为空！");
        }

        if (StringUtils.isNotEmpty(studentVo.getAge())) {
            student.setAge(Integer.valueOf(studentVo.getAge()));
        } else {
            failureReasonContent.add("' 学生年龄 '不能为空！");
        }

        if (StringUtils.isNotEmpty(studentVo.getDormitoryName())) {
            student.setDormitoryName(studentVo.getDormitoryName());
        }
        if (StringUtils.isNotEmpty(studentVo.getClassName())) {
            student.setClassName(studentVo.getClassName());
        }
        if (StringUtils.isNotEmpty(studentVo.getGradeName())) {
            student.setGradeName(studentVo.getGradeName());
        }
        if (StringUtils.isNotEmpty(studentVo.getCollegeName())) {
            student.setCollegeName(studentVo.getCollegeName());
        }

        // 判断是否存在不合规的数据
        if (CollectionUtils.isNotEmpty(failureReasonContent)) {
            // 设置失败信息
            student.setFailureReasonContent(join(failureReasonContent, ';'));
            // 添加失败的数据
            failureData.add(student);
            return;
        }
        // 添加保存数据
        insertData.add(student);
    }

    @Transactional
    public String saveImportData(Map<String, List<TbStudent>> updateMap) {
        // 获取有空值的数据
        List<TbStudent> failureData = updateMap.get("failure");
        // 获取需要插入的数据
        List<TbStudent> insertData = updateMap.get("insert");
        // 返回错误数据信息
        if (CollectionUtils.isNotEmpty(failureData)) {
            // 构造错误信息表
            List<String[]> exportList = Lists.newArrayList();
            String[] titles = new String[]{"学生学号","学生姓名","学生性别","出生日期","学生年龄","学生宿舍","班级名称","年级名称","学院名称", "失败原因"};
            failureData.forEach( x-> {
                String[] row = {
                        StringUtils.isNotEmpty(x.getNumber()) ? x.getNumber() : "",
                        StringUtils.isNotEmpty(x.getName()) ? x.getName() : "",
                        getStudentSex(x),
                        ObjectUtils.isNotEmpty(x.getBirthday()) ? DateUtils.dateConvertStr(String.valueOf(x.getBirthday()),"yyyy-MM-dd HH:mm") : "",
                        ObjectUtils.isNotEmpty(x.getAge()) ? x.getAge() + "" : "",
                        StringUtils.isNotEmpty(x.getDormitoryName()) ? x.getDormitoryName() : "",
                        StringUtils.isNotEmpty(x.getClassName()) ? x.getClassName() : "",
                        StringUtils.isNotEmpty(x.getGradeName()) ? x.getGradeName() : "",
                        StringUtils.isNotEmpty(x.getCollegeName()) ? x.getCollegeName() : "",
                        StringUtils.isNotEmpty(x.getFailureReasonContent()) ? x.getFailureReasonContent() : ""
                };
                exportList.add(row);
            });
            //调用Excel导出失败的数据指定的目录下 /uploads/... 并返回文件名
            try {
                return ExcelExportUtils.listConverExcel(titles, exportList);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        // 插入学生信息
        if (CollectionUtils.isNotEmpty(insertData)) {
            // 批量保存学生信息
            saveBatch(insertData);
        }
        return null;
    }

    private String getStudentSex(TbStudent student) {
        if (ObjectUtils.isNotEmpty(student.getSex())) {
            return student.getSex() == 1 ? "男" : "女";
        }
        if (ObjectUtils.isNotEmpty(student.getSexStr())) {
            return student.getSexStr();
        }
        return "";
    }

}
